No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Computer, Inc. Printed in the United States of America.
No licenses, express or implied, are granted with respect to any of the technology described in this book. Apple retains all intellectual property rights associated with the technology described in this book. This book is intended to assist application developers to develop applications only for Apple Macintosh computers.
Apple Computer, Inc.
20525 Mariani Avenue
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, LaserWriter, and Macintosh are trademarks of Apple Computer, Inc., registered in the United States and other countries.
Adobe Illustrator and PostScript are trademarks of Adobe Systems Incorporated, which may be registered in certain jurisdictions.
AGFA is a trademark of Agfa-Gevaert.
FrameMaker is a registered trademark of Frame Technology Corporation.
Helvetica and Palatino are registered trademarks of Linotype Company.
ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
Simultaneously published in the United States and Canada.
LIMITED WARRANTY ON MEDIA AND REPLACEMENT
ALL IMPLIED WARRANTIES ON THIS MANUAL, INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE LIMITED IN DURATION TO NINETY (90) DAYS FROM THE DATE OF THE ORIGINAL RETAIL PURCHASE OF THIS PRODUCT.
Even though Apple has reviewed this manual, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS MANUAL, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS MANUAL IS SOLD “AS IS,” AND YOU, THE PURCHASER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS MANUAL, even if advised of the possibility of such damages.
THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty.
Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.
Contents
Figures, Tables, and Listingsv
Chapter 1 From QuickDraw to QuickDraw GX1-1
A Brief History of QuickDraw1-3
Graphics Programming Issues1-4
What to Draw1-5
QuickDraw Shapes1-5
QuickDraw GX Shapes1-6
How to Draw1-9
Style Objects1-10
Ink Objects and Colors1-12
Where to Draw1-13
Transforms1-14
How to Program It1-16
Chapter 2 Setting Up the Sample Application2-1
The Shell Program2-3
Initializating QuickDraw GX2-3
Attaching View Ports to Windows2-4
The Drawing Functions2-5
Chapter 3 Programming With Shapes3-1
Drawing a Line3-3
Drawing a Rectangle3-6
Drawing a Framed Rectangle3-8
Drawing a Curve3-10
Drawing a Polygon3-11
Drawing a Path3-13
Drawing Text3-15
Drawing Glyphs3-16
Drawing a Layout Shape3-19
Drawing a Bitmap3-22
Drawing a Picture3-24
Chapter 4 Programming With Styles4-1
Creating a Thick Line4-3
Creating a Thick Curve4-4
Adding Dashes to a Curve4-5
Adding Caps to a Curve4-8
Adding a Pattern to a Curve4-10
Changing Text Size and Font4-13
Changing the Text Face4-14
Insetting and Outsetting the Pen4-14
Changing the Style of a Picture Element4-17
Chapter 5 Programming With Inks5-1
Drawing a Blue Curve5-3
Blending Two Shapes5-4
Changing the Ink of a Picture Element5-6
Chapter 6 Programming With Transforms6-1
Clipping a Curve6-3
Rotating a Curve6-5
Skewing Text6-7
Transforming an Element of a Picture6-8
Hit-Testing6-9
Chapter 7 Printing7-1
Preparing to Print7-3
Setting Up a Document7-4
Printing One Copy7-5
Displaying the Print Dialog Box7-7
Figures, Tables, and Listings
Chapter 1 From QuickDraw to QuickDraw GX1-1
Figure 1-1 The shape object1-8
Figure 1-2 The style object1-11
Figure 1-3 QuickDraw pen versus QuickDraw GX pen1-12
Figure 1-4 An ink object1-12
Figure 1-5 A transform object1-15
Chapter 2 Setting Up the Sample Application2-1
Chapter 3 Programming With Shapes3-1
Listing 3-1 The CreateLine function3-4
Figure 3-1 A line shape3-4
Listing 3-2 The DoDraw function3-5
Listing 3-3 The CenterShapeInWindow function3-5
Listing 3-4 The CreateRectangle function3-6
Figure 3-2 A rectangle shape3-6
Listing 3-5 The SetUpEraserAndInvalWindow function3-7
Listing 3-6 The DoDraw function3-7
Listing 3-7 The CreateAFramedRectangle function3-9
Figure 3-3 A framed rectangle3-9
Listing 3-8 The CreateCurve function3-10
Figure 3-4 A curve shape3-11
Listing 3-9 The CreatePolygon function3-12
Figure 3-5 A polygon shape3-13
Listing 3-10 The CreatePath function3-14
Figure 3-6 A path shape3-15
Listing 3-11 The CreateText function3-15
Figure 3-7 A text shape3-16
Listing 3-12 The CreateGlyphs function3-17
Figure 3-8 A glyph shape3-19
Listing 3-13 The CreateLayout function3-20
Figure 3-9 A layout shape3-22
Listing 3-14 The CreateBitmap function3-23
Figure 3-10 A bitmap shape3-24
Listing 3-15 The CreatePicture function3-25
Figure 3-11 A picture shape3-26
Listing 3-16 The SetUpEraserAndInvalWindow function for picture shapes3-27
Chapter 4 Programming With Styles4-1
Listing 4-1 The CreateAThickLine function4-3
Figure 4-1 A thick line4-4
Listing 4-2 The CreateAThickCurve function4-5
Figure 4-2 A thick curve4-5
Listing 4-3 The CreateADashedCurve function4-6
Figure 4-3 A dashed curve4-7
Listing 4-4 The CreateACappedCurve function4-8
Figure 4-4 A capped curve4-10
Listing 4-5 The CreateAPatternedCurve function4-11
Figure 4-5 A patterned curve4-12
Listing 4-6 The ChangeTextSizeAndFont function4-13
Figure 4-6 Enlarged text4-13
Listing 4-7 The ChangeTextStyle function4-14
Figure 4-7 Italic, extended, enlarged text4-14
Listing 4-8 The PenGeometryPathPlay function4-15
Figure 4-8 Path with pen inset, centerd, and outset4-16
Listing 4-9 The AddThickBorderInPicture function4-17
Figure 4-9 A house with a thick border4-18
Chapter 5 Programming With Inks5-1
Listing 5-1 The CreateABlueCurve function5-3
Figure 5-1 A blue curve5-4
Listing 5-2 The CreateABlendedCurve function5-4
Figure 5-2 Blended curves5-6
Listing 5-3 The AddInkToDoorInPicture function5-6
Figure 5-3 A house with a turquoise door5-7
Chapter 6 Programming With Transforms6-1
Listing 6-1 The ClipCurve function6-3
Figure 6-1 A clipped curve6-5
Listing 6-2 The RotateCurve function6-6
Figure 6-2 A rotated curve6-7
Listing 6-3 The SkewText function6-7
Figure 6-3 Skewed text6-8
Listing 6-4 The AddNewWindowToPicture function6-8
Figure 6-4 A house with two windows6-9
Listing 6-5 The HitTestLayoutCaret function6-10
Figure 6-5 A layout with a caret6-11
Chapter 7 Printing7-1
Listing 7-1 The CreateNewPrintJob function7-3
Listing 7-2 The DisposePrintJob function7-4
Figure 7-1 The Document Setup dialog box7-4
Listing 7-3 The DoDocumentSetUp function7-5
Listing 7-4 The DoPrintOneCopy function7-6
Figure 7-2 The Print dialog box7-7
Listing 7-5 The DoPrintShape function7-8
Listing 1-0
Table 1-0
From QuickDraw to QuickDraw GX
Contents
A Brief History of QuickDraw1-3
Graphics Programming Issues1-4
What to Draw1-5
QuickDraw Shapes1-5
QuickDraw GX Shapes1-6
How to Draw1-9
Style Objects1-10
Ink Objects and Colors1-12
Where to Draw1-13
Transforms1-14
How to Program It1-16
From QuickDraw to QuickDraw GX
TO THE READER:
This book has not been substantially updated since the previous seed release, in May 1993. Parts of it are out of date and some code samples are incorrect or demonstrate suboptimal coding techniques. A major revision and expansion of this document is planned before its final release.u
QuickDraw GX is the new imaging technology from Apple Computer. It is not a revision of QuickDraw, but rather a complete redesign of the Macintosh graphics architecture.
This chapter compares QuickDraw GX to QuickDraw. The first section, “A Brief History of QuickDraw,” discusses how the design goals of QuickDraw have changed with each version.
The second section, “Graphics Programming Issues” on page 1-4, introduces the basic challenges inherent in graphics programming. The QuickDraw GX approach to solving these problems is compared to the QuickDraw approach in the sections “What to Draw” on page 1-5, “How to Draw” on page 1-9, and “Where to Draw” on page 1-13.
The final section in this chapter, “How to Program It” on page 1-16, outlines the programming support included with QuickDraw GX.
A Brief History of QuickDraw
The original version of QuickDraw was designed to achieve two specific goals:
n to provide the graphics capabilites necessary for the original Macintosh user interface
n to produce graphics quickly and efficiently—on computer hardware that, by today’s standards, was quite limited
The original QuickDraw could produce the kinds of graphics required for the Macintosh user interface: rectangles for windows, round rectangles for buttons, patterns for the desktop, and so on. In the interest of speed, the scope of the original QuickDraw did not include many advanced graphics capabilities.
To address some of these limitations, Apple has released two major revisions of QuickDraw: Color QuickDraw, which added color capabilities, and 32-bit QuickDraw, which supports true color. Both Color QuickDraw and 32-bit QuickDraw are extensions of the original QuickDraw—that is, they share the basic architecture of the original QuickDraw, each adding new capabilities.
Color QuickDraw in System 7 unified the previous versions and provided some additional capabilites, but it was based on the original QuickDraw architecture as well.
With QuickDraw GX, Apple is providing an entirely new graphics architecture—and a great number of new graphics capabilities. QuickDraw GX is related to the earlier versions of QuickDraw not in the design of the architecture, but rather in overall objective. QuickDraw GX has design goals similar to the design goals for QuickDraw:
n to provide the sophisticated graphics capabilites necessary for the graphical user interface of the Macintosh
n to produce these sophisticated graphics quickly and efficiently
In addition, the QuickDraw GX design has addressed some new goals:
n to provide a larger set of basic graphics objects
n to provide a consistent programming interface to those objects
n to provide device-independent graphics
n to provide useful programming tools for application developers—tools for debugging and error handling, for example
n to provide a runtime environment that supports fast graphics with many types of graphics objects
n to provide consistent printing for all graphics objects
So, where earlier versions of QuickDraw offer one set of solutions to common graphics programming issues, QuickDraw GX offers another. The rest of this chapter discusses these common graphics programming issues and compares the QuickDraw GX approach to the QuickDraw approach.
Graphics Programming Issues
Any graphics environment must provide a mechanism for you, as a graphics programmer, to specify three things:
n What to draw. You must be able to define the object to draw, which might include specifying control points (like the beginning and end of a line), specifying characters (when drawing text), or specifying bit patterns (when drawing bitmaps).
n How to draw it. A full-featured graphics environment should allow you to apply a number of stylistic and other variations to your graphics objects. For example, you might want to specify how thick an object’s border should be, what pattern should fill an object, or what color an object should be.
n Where to draw it. You also need to specify where the graphic should be drawn: what spatial relation it should have to other graphics objects and on what device it should actually be rendered.
There’s a fourth concern of full-featured graphics environments as well:
n How to program it. A graphics environment needs to provide programming tools (such as debugging tools) and development and runtime environments that support the graphics programming process.
The next three sections discuss the three drawing issues and how the QuickDraw GX approach differs from the original QuickDraw approach, and the final section in this chapter discusses the programming support included with QuickDraw GX.
What to Draw
From a programmer’s point of view, the most fundamental difference between the QuickDraw architecture and the QuickDraw GX architecture is the way you describe the graphics shapes you want to draw.
QuickDraw GX makes an important improvement on QuickDraw in this regard. Where the earlier QuickDraw architecture sometimes muddies the distinction between defining a shape and drawing a shape, QuickDraw GX keeps these tasks clearly separated.
To illustrate this distinction, the next section, “QuickDraw Shapes,” examines how you define shapes with QuickDraw and the section “QuickDraw GX Shapes,” on page 1-6, examines how you define them with QuickDraw GX.
QuickDraw Shapes
In the earlier versions of QuickDraw, the way you define a shape depends on what type of shape you want to draw.
The procedurally drawn shapes don’t require an explicit data structure—the shape is defined solely by calling drawing routines. To draw a line, for example, you could call the following routines:
MoveTo(10,10);
LineTo(20,20);
Notice that the definition of the line is not distinct from the drawing of line: the same code that defines the line also draws it.
The rectangle-based shapes (rectangles, round rectangles, and ovals) make some distinction between defining a shape and drawing it. With these types of shapes, you first define the shape’s bounding rectangle with a Rect data structure, for example:
Rect aRect;
SetRect(&aRect, 10, 10, 20, 20);
Then you finish defining the shape as you draw it. For example,
FrameRect(&aRect);
uses the aRect structure to draw a framed rectangle, whereas
FillOval(&aRect);
uses the same data structure to draw a filled oval.
The handle-based shapes (which include polygons and regions) require the most definition. To draw a region shape, for example, you must first allocate a new region, then define the parts of the region, and finally draw the region with a routine such as FrameRgn or FillRgn.
The QuickDraw approach to describing and drawing shapes has three important limitations:
n It is not a unified model: each type of shape requires a different method of programming.
n It allows direct access to many data structures, which prevents the data structures from residing on an accelerator card.
n It relies on state information—information stored in the graphics environment that affects how shapes are drawn. Since each graphics shape stores little information itself about how it is to be drawn, the graphics environment must store that information—and your application must set up the graphics environment correctly before drawing each shape.
QuickDraw GX Shapes
Unlike QuickDraw, QuickDraw GX separates the process of defining a shape from the process of drawing the shape. QuickDraw GX provides methods for defining and drawing shapes that are consistent across shape types—you can create a line in the same manner that you create a polygon and you can draw a rectangle with the same function that draws a bitmap.
The different types of shapes you can define with QuickDraw GX include:
n empty shapes
n full shapes
n points
n lines
n rectangles
n curves
n polygons
n paths
n text
n glyphs
n layouts
n bitmaps
n pictures
Chapter 3 of this document, “Programming With Shapes,” describes these shape types in more detail and provides sample code that shows how to create them.
In QuickDraw GX, every type of shape requires a definition and an underlying data structure—in this way, shapes in QuickDraw GX are similar to the handle-based shapes of QuickDraw. However, there are many important differences.
The data structures that represent shapes in QuickDraw GX are private—that is, your application cannot directly manipulate the information stored in them. These data structures are called objects and the pieces of information in them are called properties. QuickDraw GX provides functions that allow your application to create and dispose of objects and to change the values of their properties.
Each QuickDraw GX shape is represented by a shape object. Every shape object has six properties:
n shape type, which specifies the type of the shape: line, rectangle, curve, and so on
n geometry, which describes the graphical structure of the shape—for example,
the geometry of a curve shape contains the control points that define the curve; the geometry of a text shape contains the characters that make up the text
n shape fill, which specifies how the shape should be framed or filled
n attributes, which are a set of flags that modify the behavior of the shape
n owner count, which QuickDraw GX uses to implement object sharing
n tag list, which you can use to add application-specific information to your shapes
In addition to these six properties, every shape object contains references to three other objects: a style object, an ink object, and a transform object. These objects are discussed later in this chapter.
Figure 1-1 depicts a shape object and shows how the shape type, shape fill, and geometry properties affect the shape.
Note
Note that the word shape has two different meanings in QuickDraw GX. The word shape can refer to any graphic, such as a blue rectangle drawn on the screen, but it can also refer to the shape object, which exists in memory, has the type gxShape, and contains the the six properties listed above. In QuickDraw GX, every graphic shape is represented in memory by a shape object, so the term shape is used for both. u
Figure 1-1 The shape object
There are three main advantages to defining shapes separately from drawing them:
n A consistent programming interface. To draw a shape with QuickDraw GX, no matter what the shape type, you create a shape object, set the values of its properties appropriately, and then draw the shape. QuickDraw GX provides a number of methods for creating shape objects and initializing their properties, but each method works for the entire range of shape types.
n No reliance on state information. Since some shapes in QuickDraw have no data structure associated with them, QuickDraw must use other elements of the graphic environment to store information about how to draw the shapes. For example, a QuickDraw line has no associated data structure, so QuickDraw uses the GrafPort data structure to store information such as how thick the line should be drawn. Whenever you want to draw a new line with a different thickness, you must remember to set the information in the GrafPort structure first. With QuickDraw GX, however, every shape is represented by a shape object, which, along with its associated style, ink, and transform objects, includes all of the information necessary to draw the shape. The next two sections discuss the style, ink, and transform objects in more detail.
n A place to cache pre-drawing calculations. Certain calculations are necessary before drawing any shape—for some shapes, these calculations can take as much time as the actual drawing. Because drawing in QuickDraw relies on information stored in the graphics environment, pre-drawing calculations typically must be thrown away after drawing each shape. However, in QuickDraw GX, the pre-drawing calculations for each shape can be stored as a cache associated with the shape object. If memory permits, these caches stay around from one drawing of a particular shape to the next. The next time you draw a shape that you have already drawn (for example, in response to an update event), QuickDraw GX can use the information in the cache to speed the drawing process. Although QuickDraw GX handles these caches for you, it also provides a mechanism for you to create and dispose them to suit your application’s particular needs. You can find more information about these drawing caches in Inside Macintosh: QuickDraw GX Objects.
As you can see, the advantages of QuickDraw’s object-based graphics are numerous. However, there are some potential disadvantages to this type of graphics system. For example, since every shape stores all of the information necessary to draw it, the amount of memory necessary for complex graphics could be very large. QuickDraw GX addresses this problem in two ways: it automatically unloads shapes (writes them to disk) when it needs more memory space, and it allows objects to be shared. For more information about loading and unloading shapes, see Inside Macintosh: QuickDraw GX Objects; for more information about object sharing, see that book and also see the next section of this chapter.
Another potential disadvantage of object-based graphics is that the sheer number of objects in memory might pose special memory-management problems. To address this concern, QuickDraw GX has its own specialized memory manager, and QuickDraw GX objects reside in a private memory heap. For more information, see “How to Program It” on page 1-16.
How to Draw
With QuickDraw, much of the information necessary to draw shapes is stored in a GrafPort (or CGrafPort) data structure. For each GrafPort data structure, there can be only one set of drawing state information at a time. This information, such as pen size and pattern, applies to whatever shape happens to be drawn while the information is in the GrafPort structure.
When you want to draw a shape, you must prepare information in the GrafPort structure before calling the routines that draw the shape. Since a GrafPort structure typically applies to an entire window, you have to reset the information in the GrafPort structure before you draw a different shape in the same window.
As discussed in the previous section, having to constantly reset the values in the GrafPort structure is a programming chore and it eliminates the possibility of caching certain types of pre-drawing calculations.
With QuickDraw GX, each shape is responsible for maintaining its own drawing information. For example, pen size no longer applies to the entire drawing port—instead, each individual shape can have its own pen size. When you want to draw a shape, you don’t need to reset any state information; you simply call the shape-drawing function.
Instead of storing this type of drawing information in the shape object directly, QuickDraw GX encapsulates it into two other types of objects:
n The style object. These objects store information about stylistic variations on how the shape is drawn. Some of this information is similar to the information in the QuickDraw GrafPort data structure, such as pen size, pattern, text font, and text size; some information is new to QuickDraw GX, such as dashes, joins, and caps. The next section, “Styles,” describes style objects in more detail.
n The ink object. These objects store color and transfer mode information. QuickDraw GX provides a sophisticated method for color specification, which allows you to specify colors in a wide variety of color spaces. Transfer modes are an enhanced version of the copy modes of QuickDraw. The section “Ink Objects and Colors,” on page 1-12, describes ink objects in more detail.
One of the advantanges of storing style and ink information separately from shape information is that it permits sharing—for example, a single style object can be shared among many shape objects. Object sharing minimizes the amount of memory QuickDraw GX needs to describe graphic shapes.
When you first create a QuickDraw GX shape, the new shape object contains a reference to the system’s default style object and default ink object. These objects, which are typically shared by many shapes, contain default drawing information—for example, the default pen thickness is 1.0 and the default color is black. If you want to change the system’s default stylistic and color behavior, you only need to change the properties of these default objects.
QuickDraw GX provides a great number of functions that allow you to customize the style and ink properties of a shape. For example, if you want to change the pen thickness property of a particular shape, you use the GXSetShapePen function. If the shape is currently sharing its style object with other shapes, QuickDraw GX typically creates a copy of the shared style object, assigns it the new pen thickness, and associates it with the shape.
The next two sections examine the properties of the style and ink objects.
Style Objects
The style object contains information about stylistic variations applicable to both geometric shapes and typographic shapes.
Figure 1-1 depicts a style object and shows how certain style properties affect shape drawing.
Figure 1-2 The style object
There is an important difference between the QuickDraw pen and the QuickDraw GX pen. Conceptually, the QuickDraw pen is an upright rectangle that QuickDraw drags along the contours of the shape being drawn. The QuickDraw GX pen is a line which QuickDraw GX drags along the contours of the shape being drawn—always keeping it perpendicular to the contours; you can specify whether it is centered, inset, or outset. Figure 1-3 shows the difference between these two pens.
Figure 1-3 QuickDraw pen versus QuickDraw GX pen
The sample functions in Chapter 4, “Programming With Styles,” demonstrate the QuickDraw GX pen, along with other properties of the style object.
Ink Objects and Colors
The ink object contains information about a shape’s color and how that color interacts with the background when the shape is drawn.
Figure 1-1 depicts an ink object and shows how the color and transfer mode properties affect drawing.
Figure 1-4 An ink object
With QuickDraw, you typically specify colors in the RGB color space; either directly, when the color specification contains actual RGB color information, or indirectly, when the color specification contains an index into a table that holds the RGB color information.
QuickDraw GX retains both the direct and indirect color specification models, but also adds a number of new color spaces, as well as a color matching model. The chapter “Colors and Color-Related Objects” in Inside Macintosh: QuickDraw GX Objects describes the new color model in detail.
The transfer modes of QuickDraw GX allow you to specify how a shape’s color interacts with the existing background color when drawn.
The sample functions in Chapter 5, “Programming With Inks,” show how to set the color and transfer mode of a QuickDraw GX shape.
Where to Draw
In QuickDraw, the GrafPort data structure also contains information that determines where shapes are drawn. The GrafPort has its own coordinate system, contains a bitmap, and is typically associated with a window, an offscreen drawing buffer, or a printing device. Whenever you draw a shape, you are drawing to the “current GrafPort.”
QuickDraw GX provides the view port and the view device to replace this use of the GrafPort. The view port defines a local coordinate space and determines other characteristics of how shapes are rendered in the view port, such as whether the shapes are dithered. Like a GrafPort, a view port can be associated with a particular window; however, it does not have to be. You can create view port hierarchies to implement features such as separate scrolling panes in a window.
The view device represents a rendering device or an offscreen equivalent. Like the GrafPort, it contains a bitmap that represents the result of drawing operations. The “View-Related Objects” chapter of Inside Macintosh: QuickDraw GX Objects describes view ports, view devices, and the relationship between them.
Just as each shape in QuickDraw GX is responsible for maintaining its own style and color information, each shape is also responsible for maintaining information about where it is to be drawn. This information is encapsulated in the transform object.
Each QuickDraw GX shape references a transform object, which specifies how the shape is to be clipped and mapped, and to what view port the shape is to be drawn. The next section, “Transforms,” explains the transform object in more detail.
Another important difference between QuickDraw and QuickDraw GX is how you specify coordinates. In QuickDraw, coordinates are integers whereas in QuickDraw GX coordinates are fixed-point values (type fixed ), which have both an integer and a fractional part.
Sometimes the “where” of “where to draw” isn’t the screen or an offscreen buffer, but rather a printer. QuickDraw GX provides an entirely new printing architecture, which is introduced in Chapter 7, “Printing,” and thoroughly described in Inside Macintosh: QuickDraw GX Printing.
Transforms
The transform object contains information about how a shape is to be clipped, what mapping transformation should be applied to it, and to what viewPorts it should be drawn.
Figure 1-1 depicts a transform object and shows how certain transform properties affect shape drawing.
Figure 1-5 A transform object
Because each QuickDraw GX shape references a transform object, each shape can have its own clip and its own mapping. The clip determines how much of the shape is visible when drawn. A clip can be any QuickDraw GX shape (except pictures and some kinds of bitmaps). For example, you could use a polygon shape as a clip shape to show only a small triangular section of a large picture.
The mapping is a 3-by-3 matrix that QuickDraw GX applies to the coordinates of the shape’s control points before drawing the shape. With this mapping, you can skew, rotate, resize, and otherwise distort your shapes. QuickDraw GX provides a number of functions that manage this mapping for you, such as GXSkewShape and GXScaleShape, but it also provides functions that allow you to alter the mapping matrix directly.
The transform object also contains some parameters that affect hit testing. Chapter 6, “Programming With Transforms,” shows an example of hit-testing, and the “Shape Objects” and “Transform Objects” chapters of Inside Macintosh: QuickDraw GX Objects explain hit-testing and the transform’s hit test parameters in more detail.
Finally, the transform object contains a view port list. When you draw any shape, the view port list of that shape’s transform determines which view ports the shape is actually drawn to. See the chapter “View-Related Objects” Inside Macintosh: QuickDraw GX Objects for more details.
How to Program It
In addition to the new graphics architecture described in this chapter, QuickDraw GX also provides a number of new programming support features:
n Debugging support. There are two versions of QuickDraw GX: a debugging version and a nondebugging version. The debugging version is larger and slower, but contains code that supports the debugging process. QuickDraw GX also provides validation functions, which help you to ensure the integrity of your graphics objects, and a debugger, called GraphicsBug, which allows you to examine the contents of your graphics objects.
n Error-handling system. QuickDraw GX defines three levels of errors: notices, warnings, and errors. Notices alert you to unnecessary or redundant function calls. Warnings inform you that, while a function may have executed, it probably did something unexpected. Errors inform you that a function was unable to execute. You can provide handling functions for each type of error.
n Memory management. QuickDraw GX provides its own memory management optimized for the QuickDraw GX system of graphics object. Unlike the original Macintosh Memory Manager, QuickDraw GX doesn’t use handles to locate blocks of memory; instead it uses reference values. Although you can still use the Macintosh Memory Manager, you may want to take advantange of some of the new memory management features of QuickDraw GX to handle your application’s memory needs.
n QuickDraw simulation. QuickDraw GX provides a set of libraries that simulate the standard QuickDraw functions.
n QuickDraw translation. QuickDraw GX can automatically convert QuickDraw calls to QuickDraw GX calls and can also convert data in QuickDraw picture format to QuickDraw GX pictures.
n Utilities. QuickDraw GX also provides a number of programming utilities—for example, a messaging system, an object-collection system, and a set of mathematical support functions.
n Libraries. Finally, QuickDraw GX provides a large library of sample functions for you to use. These functions vary from the convenience functions of the shape library, which provide alternate methods of creating and initializing shapes, to the more intricate functions of the camera library, which allow you to create special perspective effects.
See Inside Macintosh: QuickDraw GX Environment and Utilities for more information on these subjects.
Listing 2-0
Table 2-0
Setting Up the Sample Application
Contents
The Shell Program2-3
Initializating QuickDraw GX2-3
Attaching View Ports to Windows2-4
The Drawing Functions2-5
Setting Up the Sample Application
The rest of this document presents a sample application that includes functions illustrating each of the major programming concepts of QuickDraw GX.
Before diving into the sample functions, however, you need to understand a little about the organization of the sample application. The application has three parts: the shell program, which is located in the QD GX Overview Main.c file, the sample drawing functions, which are located in the QD GX Overview Draw.c file, and the printing-related functions, which are located in the QD GX Overview Print.c file. This chapter introduces a few important concepts underlying the organization of the main and drawing files; the last chapter of this document, “Printing,” discusses the functions in the printing file.
The Shell Program
The shell program, which is located in the files QD GX Overview Main.h and QD GX Overview Main.c, implements most of the standard Macintosh programming necessary for the sample application. In particular, it initializes the Macintosh, creates menus, creates a window, and handles events.
The menus created by the sample application are
n File
n Edit
n Shape
n Style
n Ink
n Transform
The File and Edit menus have the usual menu items, which are disabled for this application, with the exception of the printing-related ones, which are described in Chapter 7, “Printing.”
The other four menus, Shape, Style, Ink, and Transform, contain menu items that demonstrate the four basic QuickDraw GX objects. When the user selects an item from one of these menus, the shell program calls the corresponding sample drawing functions, which are described throughout the next four chapters.
Although the shell program mostly handles typical Macintosh-related programming chores, so that you can concentrate on the QuickDraw GX-related ones, there are a few QuickDraw GX tasks handled in the shell—in particular, initializing QuickDraw GX and attaching a view port to a window. The next two sections discuss these tasks.
Initializating QuickDraw GX
The shell program calls these functions to initialize QuickDraw GX:
The GXNewGraphicsClient function sets up the graphics memory heap, in which QuickDraw GX stores your application’s graphics objects. The QuickDraw GX heap is separate from your application’s heap.
It is not strictly necessary to call the GXNewGraphicsClient function; if you don’t call it before calling the GXEnterGraphics function, QuickDraw GX sets up a default graphics heap for your application (which is based on your application’s ideal heap size).
The GXEnterGraphics function otherwise initializes QuickDraw GX—in particular, it initializes the default graphics objects.
When the user chooses to quit the sample application, the shell program calls the corresponding exit functions of QuickDraw GX:
GXExitGraphics();
GXDisposeGraphicsClient(gGraphicsClient);
The GXExitGraphics function disposes of any global variables and default objects used by QuickDraw GX, and the GXDisposeGraphicsClient function disposes your graphics memory heap.
For more information on these initialization and exit functions, see Inside Macintosh: QuickDraw GX Environment and Utilities.
The shell program also initializes some of the debugging and error-handling facilities of QuickDraw GX. In particular, it calls
SetGraphicsLibraryErrors();
SetGraphicsLibraryNotices();
These functions install the notice-, warning-, and error-handling functions provided by the QuickDraw GX libraries.
The shell program also calls
GXSetValidation(gxPublicValidation);
This function causes QuickDraw GX to perform run-time validation for all of the QuickDraw GX graphics (and typographic) function calls. Of course, this validation slows the application, but it is particularly useful when debugging a QuickDraw GX application.
Attaching View Ports to Windows
The shell program creates a standard Macintosh window with the following line of code:
In QuickDraw GX, however, you don’t draw directly to a window, but rather to a view port. QuickDraw GX provides the GXNewWindowViewPort function to create a view port and attach it to a particular window.
Since the sample application draws every shape to the same window, the shell program defines the view port attached to that window to be the default view port, by calling the SetDefaultViewPort function.
This line of code creates a new view port object, attaches it to the window referenced by the global variable gWindowOne, and adds it to the view port list of the default transform object. Since new shapes automatically reference the default transform object when you create them, QuickDraw GX draws each new shape in the sample application to the window specified by the gWindowOne parameter.
The Drawing Functions
When the user of the sample application chooses a menu item, the shell program calls the appropriate drawing function from the QD Overview Draw.c file. These drawing functions, which are described in the next four chapters, create different types of QuickDraw GX shapes. Each function stores a reference to the shape it creates in the global variable gShape:
gxShape gShape;
When the shell program receives an update event, it calls the DoDraw function, which uses the gShape variable to redraw the most recently drawn shape:
void DoDraw ()
{
if (GXGetShapeType (gShape) != gxEmptyType) {
GXValidateShape (gShape);
GXDrawShape (gShape);
}
}
In addition to the initialization that the shell program does itself, it also allows the Draw.c file to perform its own initialization:
void DoInitialization()
{
InitCommonColors();
gShape = GXNewShape (gxEmptyType);
}
The InitCommonColors function initializes the color library functions, which you’ll use in Chapter 5, “Programming With Inks.”
The shell program also calls the following function from the QD Overview Draw.c file before the application quits:
void DoDispose()
{
if (gShape != nil)
GXDisposeShape (gShape);
DisposeCommonColors();
}
Throughout the next four chapters, you’ll see the QD Overview Draw.c file one sample function at a time. Occasionally, a new sample function will require an additional include file, global variable, or initialization or exit code. Remember that you can always find the complete sample code in the QD Overview Main.c file and the QD Overview Draw.c file.
Listing 3-0
Table 3-0
Programming With Shapes
Contents
Drawing a Line3-3
Drawing a Rectangle3-6
Drawing a Framed Rectangle3-8
Drawing a Curve3-10
Drawing a Polygon3-11
Drawing a Path3-13
Drawing Text3-15
Drawing Glyphs3-16
Drawing a Layout Shape3-19
Drawing a Bitmap3-22
Drawing a Picture3-24
Programming With Shapes
This chapter shows you how to implement the Shape menu of the sample application. Each section of this chapter presents a function that creates a different type of QuickDraw GX shape, implementing a single menu item from the Shape menu. Each section introduces a new shape type, shows the code necessary to create a shape of that type, discusses the code, and tells where to find other relevant information.
Drawing a Line
QuickDraw GX provides a number of different types of shapes: geometric shapes, typographic shapes, bitmaps, and so on. Each of these shape categories has a different type of geometry. For example, the geometry of a geometric shape contains the shape’s control points; the geometries of the typographic shapes contain the characters that make up the text string, a starting position, and possibly some text style information; the geometries of bitmaps contain the pixel image, the bitmap dimension, and color information; and so on.
Lines are geometric shapes; their geometries contain two control points—a first point and a last point. QuickDraw GX provides the gxLine structure to contain a line geometry:
typedef struct {
fixed x;
fixed y;
} gxPoint;
typedef struct {
gxPoint first;
gxPoint last;
} gxLine;
The CreateLine sample function, shown in full in Listing 3-1, defines this line geometry:
where ff() is a QuickDraw GX-provided utility function that converts an integer into a number of type fixed. To create a line shape once you have defined a line geometry, you can use the GXNewLine function, which has this interface:
gxShape GXNewLine(const gxLine *data);
The following code, which appears in the CreateLine sample function, creates a new line shape from the data in the lineGeometry structure, and sets the global variable gShape to reference the new shape.
gShape = GXNewLine(&lineGeometry);
Listing 3-1 shows the complete definition of the CreateLine function, which the shell program (in the QD GX Overview Main.c file) calls in response to the user selecting the “Draw a Line” menu item from the “Shape” menu.
The CreateLine function first declares the lineGeometry structure and initializes it with fixed values using QuickDraw GX’s ff() macro. Then, it calls the InvalidWindowRect function (provided for you in the QD GX Overview Main.c file) to invalidate the window and causes an update event. The shell program responds to update events by calling the DoDraw function, which is shown in Listing 3-2.
Listing 3-2 The DoDraw function
void DoDraw()
{
if (GXGetShapeType (gShape) != gxEmptyType) {
GXValidateShape (gShape);
GXDrawShape (gShape);
}
}
This function uses the GXDrawShape function to draw the shape referenced by the gShape global variable (as long as that variable does not reference an empty shape).
After invalidating the window, the CreateLine function creates a new line shape referenced by the global variable gShape.
Finally, the CreateLine function moves the line to the center of the window, by calling the CenterShapeInWindow function, shown in Listing 3-3.
x = (windowBoundsRect.left + windowBoundsRect.right) >> 1;
y = (windowBoundsRect.top + windowBoundsRect.bottom) >> 1;
MoveShapeCenterTo(gShape, x, y);
GXDisposeShape (windowBoundsShape);
}
This function finds the center of the window and then uses the MoveShapeCenterTo function to move the center of the shape to the center of the window. The MoveShapeCenterTo function is a utility function provided in the QuickDraw GX shape library.
For more information about shapes in general, see the chapter “Shape Objects” in Inside Macintosh: QuickDraw GX Objects. For more information about line shapes, see the chapter “Geometric Shapes” in Inside Macintosh: QuickDraw GX Graphics.
You can find out about more utility functions by examining the QuickDraw GX libraries directly.
Drawing a Rectangle
You define a QuickDraw GX rectangle in much the same way that you define a line: a set of two points. However, for a rectangle, these points represent corners of the rectangle rather than first and last points. See Listing 3-4.
Listing 3-4 The CreateRectangle function
void CreateRectangle()
{
gxRectangle rectangleGeometry = {ff(25), ff(25),
ff(125), ff(125)};
SetUpEraserAndInvalWindow();
GXSetRectangle(gShape, &rectangleGeometry);
GXSetShapeFill(gShape, solidFil);
CenterShapeInWindow();
}
Figure 3-3 shows the result of this function.
Figure 3-2 A rectangle shape
Notice the similarities between the CreateRectangle function and the CreateLine function in Listing 3-1: the CreateRectangle function begins by defining the shape’s geometry, it then invalidates the window, creates a shape to contain the geometry, sets the shape fill, and centers the shape in the window. Like CreateLine, this function leaves the drawing to the DoDraw function, which the shell program calls in response to update events.
There is one major difference between the CreateLine and the CreateRectangle functions: the way they invalidate the window. When CreateLine was the only drawing function, it was enough simply to call the InvalidWindowRect function, which the shell program provides. However, now that there are two shapes that the sample application user can draw, the DoDraw function needs to erase the previous shape before drawing the next one. The sample application implements this by declaring a second global variable that stores a copy of the original shape and sets its color to white:
gxShape gEraserShape;
The gEraserShape shape is created and initialized in the SetUpEraserAndInvalWindow function, shown in Listing 3-5.
Listing 3-5 The SetUpEraserAndInvalWindow function
You should be sure to replace the call to InvalidWindowRect in your CreateLine function with a call to the SetUpEraserAndInvalWindow function—in case the sample application user chooses the Draw a Line menu item after the Draw a Rectangle menu item.
To update the window correctly, the DoDraw function has only to draw the eraser shape before drawing the new shape. See Listing 3-6.
Listing 3-6 The DoDraw function
void DoDraw()
{
if (gEraserShape != nil) {
GXValidateShape (gEraserShape);
GXDrawShape (gEraserShape);
}
if (GXGetShapeType (gShape) != gxEmptyType) {
GXValidateShape (gShape);
GXDrawShape (gShape);
}
}
You must also update your DoInitialize and DoDispose functions to include the gEraserShape object.
For more information about rectangle shapes, see the chapter “Geometric Shapes” in Inside Macintosh: QuickDraw GX Graphics.
Drawing a Framed Rectangle
The properties of the shape object determine not only the type of the shape and the control points of its geometry, but also how the shape is framed or filled. In fact, QuickDraw GX provides a number of methods for filling a shape. Some common fill types are
n gxNoFill specifies that the geometry is not to be filled at all; QuickDraw GX does not draw shapes with a gxNoFill shape fill. You can use this shape fill to hide a shape or to prevent part of a picture from drawing.
n gxHollowFill specifies that QuickDraw GX should interpret the shape’s geometry as a closed frame—a set of lines and curves connecting the shape’s control points, including a line or curve connecting the first control point and the last control point of each contour. The example function in this section, shown in Listing 3-7, uses the gxHollowFill shape fill to specify a framed rectangle.
n gxOpenFrameFill specifies that QuickDraw GX should frame the shape but not connect the first and last control points of each contour. This shape fill is appropriate for lines and curves, and for open polygons and paths.
n gxSolidFill species that QuickDraw GX should interpret the shape’s geometry as a solid area. However, this shape fill doesn’t fill areas created when a shape’s boundary overlaps itself, as shown in Figure 1-1 in the chapter “From QuickDraw to QuickDraw GX” in this book.
n gxWindingFill also specifies that QuickDraw GX interpret the shape’s geometry as a solid area, but gxWindingFill also fills areas created when the shape’s boundary overlaps itself.
QuickDraw GX provides the GXGetShapeFill and GXSetShapeFill functions to allow you to manipulate a shape’s fill type. Listing 3-7 shows the CreateAFramedRectangle sample function, which uses the GXSetShapeFill function and the gxHollowFill shape fill to create a framed rectangle.
Listing 3-7 The CreateAFramedRectangle function
void CreateAFramedRectangle()
{
if (GXGetShapeType(gShape) != gxRectangleType)
CreateRectangle();
else
SetUpEraserAndInvalWindow ();
GXSetShapeFill(gShape, gxHollowFill);
}
This example first uses the GXGetShapeType function to examine the shape type of the shape object referenced by the gShape global variable. If gShape does not already reference a rectangle shape, the CreateAFramedRectangle function calls the CreateRectangle function; if gShape does already reference a rectangle shape, the CreateAFramedRectangle function simply prepares the window to be redrawn by calling SetUpEraserAndInvalWindow.
Once gShape references a rectangle shape, the CreateAFramedRectangle function sets the shape fill to the gxHollowFill fill type. Figure 3-3 shows the result of this function.
Remember that the shell program calls the DoDraw sample function in response to the update event caused by the window invalidation, and the DoDraw function draws the shape by calling GXDrawShape(gShape).
Figure 3-3 A framed rectangle
For more information about shape types and shape fills, see the chapter “Geometric Shapes” in Inside Macintosh: QuickDraw GX Graphics.
Drawing a Curve
QuickDraw GX provides quadratic Bézier curves—the same type of curve used by Apple TrueType fonts. You specify a curve geometry with three control points:
typdef struct {
gxPoint first;
gxPoint control;
gxPoint last;
} gxCurve;
The points defined bvy the first and last fields fall at the endpoints of the curve The point defined by the control field lies off the curve; it determines the tangents of the curve at the first and last points.
Listing 3-8 shows the CreateCurve function, which defines a curve shape.
Listing 3-8 The CreateCurve function
void CreateCurve()
{
gxCurve curveGeometry = {ff(25), ff(125),
ff(100), 0,
ff(225), ff(125)};
SetUpEraserAndInvalWindow();
GXSetCurve(gShape, &curveGeometry);
GXSetShapeFill(gShape, gxOpenFrameFill);
CenterShapeInWindow();
}
The CreateCurve function first defines a curve geometry and then uses the GXSetCurve function to
n set the shape type of the gShape shape object to gxCurveType
n set the geometry of the gShape shape object to the values in curveGeometry
Although the GXSetCurve function sets the shape’s shape type and geometry, it does not affect the shape’s shape fill. Since some shape fills are not appropriate for curves, the CreateCurve function specifies the gxOpenFrameFill shape fill for the gShape shape object.
Figure 3-4 shows the result of the CreateCurve function.
Figure 3-4 A curve shape
For more information about curve shapes and curve geometries, see the chapter “Geometric Shapes” in Inside Macintosh: QuickDraw GX Graphics.
Drawing a Polygon
In QuickDraw GX, a polygon is a series of points connected by straight lines. The shape fill determines whether the polygon is open (the first and last control points are not connected) or closed (they are connected).
A polygon can have any number of control points:
typedef struct {
long vectors;
gxPoint vector[gxAnyNumber];
} gxPolygon;
The gxPolygon structure defines a single contour (a series of connected points). However, a QuickDraw GX polygon shape can contain any number of separate contours. Therefore, the polygon shape geometry is defined as an array of polygon geometries:
typedef struct {
long contours;
gxPolygon contour[gxAnyNumber];
} gxPolygons;
Listing 3-9 shows the CreatePolygon sample function, which creates a polygon shape that contains a single contour in the shape of a five-pointed star.
Listing 3-9 The CreatePolygon function
void CreatePolygon()
{
long starGeometry[] = { 1, /* number of contours */
5 , /* number of points */
/* the points */
ff(60), 0,
ff(90), ff(90),
ff(0), ff(30),
ff(120), ff(30),
ff(0), ff(90)};
SetUpEraserAndInvalWindow ();
GXSetPolygons(gShape, (polygons *) starGeometry);
GXSetShapeFill(gShape, gxSolidFill);
CenterShapeInWindow();
}
The CreatePolygon function defines the geometry of the polygon in the starGeometry array. The geometry specifies a single contour of five points, each point being a tip of one the points of the star.
This sample function sets the shape type and the geometry of the gShape shape object with the GXSetPolygons function. Notice that this function casts the starGeometry variable, which is declared to be an array of long values, to type gxPolygons before sending it to the GXSetPolygons function.
The CreatePolygon function also sets the shape fill of the gShape shape object to gxSolidFill with the GXSetShapeFill function. The gxSolidFill shape fill specifies that the polygon be a solid area; however, areas created when the polygon’s boundary overlaps itself are not filled. Figure 3-5 shows the result of the CreatePolygon function.
Figure 3-5 A polygon shape
For more information about shape fills and polygon shapes, see the chapter “Shape Objects” in Inside Macintosh: QuickDraw GX Objects and the “Geometric Shapes” chapters of Inside Macintosh: QuickDraw GX Graphics.
Drawing a Path
A QuickDraw GX path is similar to a polygon in that it is a connected series of points. However, paths can contain curves as well as straight lines.
A path can have any number of control points, which can lie on or off the path:
typedef struct {
long vectors;
long controlBits[gxAnyNumber];
gxPoint vector[gxAnyNumber];
} gxPath;
The gxPath structure is identical to the gxPolygon structure, except that the gxPath structure includes an array of bits that specify whether each control point is on or off the path. Two consecutive points on the path indicate a straight line. Two points on the path separated by a single point off the path indicate a quadratic Bézier curve. Two consecutive points off the path imply an on-path point halfway between them.
Like polygon shapes, path shapes can also have more than one contour. The gxPaths structure describes a path shape’s geometry:
typedef struct {
long contours;
gxPath contour[gxAnyNumber];
} gxPaths;
Listing 3-10 shows the CreatePath sample function, which creates a path shaped like a figure eight with an extra loop.
Listing 3-10 The CreatePath function
void CreatePath()
{
long tripleBumpPathGeometry[] = {1, // number of contours
This function first defines a path geometry containing a single contour with six control points. The controlBits field of this structure is set to the value 0xff000000. Clear bits in this field correspond to control points on the curve and set bits correspond to points off the curve. Since the first six bits of 0xff000000 are set, all six control points for this path are off the curve—meaning there are six implied on-curve points halfway between each consecutive pair of off-curve points.
The CreatePath sample function uses the GXSetPaths function to set the shape type and geometry of the gShape shape object and uses the GXSetShapeFill function to set its shape fill.
Figure 3-6 shows the result of the CreatePaths function.
Figure 3-6 A path shape
For more information about path geometries and path shapes, see the chapter “Geometric Shapes” in Inside Macintosh: QuickDraw GX Graphics.
Drawing Text
QuickDraw GX provides three types of typographic shapes: the text shape, the glyph shape, and the layout shape. The text shape is the simplest of these three; it represents a string of text with one font, one text size, and one typestyle.
Unlike the geometric shapes, which contain control points in their geometries, the geometry of a text shape contains a string of characters and a starting position.
Listing 3-11 shows the CreateText sample function, which creates a text shape.
This sample function uses the GXSetText function to set the shape type and the geometry of the gShape shape object. The shape type becomes gxTextType, and the geometry includes the string “QuickDraw™ GX” and a point that indicates the starting position of the text. Figure 3-7 shows the result of this function.
Figure 3-7 A text shape
Because the CreateText sample function does not set a specific font, text size, or typestyle, QuickDraw GX chooses the appropriate default for the current script system. The section “Changing Text Styles” in Chapter 4, “Programming With Styles,” shows how to override this default.
For more information about text shapes, see the chapters “Typographic Shapes” and “Text Shapes” in Inside Macintosh: QuickDraw GX Typography.
Drawing Glyphs
The glyph shape provides more sophisticated typography than the text shape. A glyph shape represents a string of text that can have multiple fonts, text sizes, font styles, glyph orientations and glyph positions.
Like text shapes, glyph shapes include a text string and a starting position in their geometries and text style information in their associated style object. However, for text shapes the text style information applies to the entire string of text, whereas for glyph shapes this style information is simply the default—a glyph shapes can have multiple styles, which override the default style information. Glyph shapes store overriding information about each glyph’s position, tangent, font, size, and style in the glyph shape’s geometry.
The CreateGlyphs sample function, shown in Listing 3-12, makes the gShape shape object into a glyph shape. The function starts by creating a text shape referenced by a local variable bunchOfGlyphs, and then converts it to a glyph shape. Then the function creates four text styles, each of which is a style object that specifies a font, a text face, and a text size.
The CreateGlyphs function then creates a style list which alternates through the four styles and assigns the style list to the glyph shape using the SetGlyphStyles function. The second parameter to this function is an array of values indicating how many glyphs each style applies to. In this example, each element of this array is filled with the value 1, indicating that each style applies to a single glyph.
The CreateGlyphs function then uses the GXGetGlyphPositions and GXSetGlyphPositions functions to vary the position of each glyph in the glyph shape.
Finally, the sample function uses the GXCopyToShape function to copy the bunchOfGlyph gxShape to the global variable gShape, and uses the GXDisposeShape function to dispose the bunchOfGlyphs shape.
Listing 3-12 The CreateGlyphs function
void CreateGlyphs()
{
char theText[] = "Just a bunch of letters";
gxPoint startingPosition = {ff(65), ff(140)};
gxPoint glyphPosition[sizeof(theText) + 1];
gxStyle styles[sizeof(theText)];
gxStyle styleSet[4];
short runsOfText[sizeof(theText)];
gxShape bunchOfGlyphs;
short counter;
long advanceBits = 0x80000000;
SetUpEraserAndInvalWindow ();
/* Create a text shape and convert it to a glyph shape. */
The SetStyleCommonFont and SetStyleCommonFace functions are utility functions included in the QuickDraw GX libraries. To include the appropriate libraries for these functions, add these lines to the beginning of your QD GX Overview Draw.c file:
#include "font library.h"
Figure 3-8 shows the result of the CreateGlyphs function.
Figure 3-8 A glyph shape
For more information about glyph shapes, see the chapters “Typographic Shapes” and “Glyph Shapes” in Inside Macintosh: QuickDraw GX Typography. You might also want to examine the functions defined in the text and font libraries.
Drawing a Layout Shape
Layout shapes provide the most sophisticated typography in QuickDraw GX. With a layout shape, you can
n highlight some or all of the text in the shape, including discontiguous highlighting
n hit-test within the text
n determine the appropriate location for a caret given some position in the text
n support your application’s line-breaking decisions with fast measurement functions
n automatically create contextual glyph forms and ligatures
n have manual or automatic kerning, tracking, and letterspacing
n correctly handle justification and ordering capabilities in right-to-left languages like Arabic and Hebrew
Much of the information used to create the special effects of layout shapes is contained in TrueType GX fonts. For example, these fonts contain
n baseline information, including a primary baseline and relative positions of other baselines, such as centered, hanging, or mathematics baselines
n justification behavior, such as how white space is distributed
n information on caret placement, such as where carets should be placed inside ligatures
n information about ligature formation and other glyph transformations
n the optical edges of glyphs
Listing 3-13 shows the CreateLayout sample function, which creates a layout shape with three separate style runs. Most of this function simply sets up the parameters to the GXNewLayout function:
gxShape GXNewLayout(long textRunCount, const short textRunLengths[],
const void *text[], long styleRunCount,
const short styleRunLengths[],
const gxStyle styles[], long levelRunCount,
const short levelRunLengths[],
const short levels[],
const gxLayoutOptions *layoutOptions,
const gxPoint *position);
The CreateLayout sample function sets these parameters:
n textRunCount, which indicates the number of different text strings in the text parameter
n testRunLengths, which indicates the number of characters in each of the text runs
n text, which contains the text strings
n styleRunCount, which indicates the number of different styles in the styles parameter
n styleRunLengths, which indicates the number of bytes of text associated with each entry in the styles parameter
n styles, which contains the style information
n position, which contains the starting position of the layout shape
The CreateLayout sample function sets up the text and style run information, and then calls the GXNewLayout function. Figure 3-9 shows the result of this function.
Figure 3-9 A layout shape
Note
An even easier way of creating a layout shape is to create a text shape using the GXNewText function and convert it to a layout shape using the GXSetShapeType function. u
Seen chapter 6, “Programming With Transforms,” for an example of hit-testing this layout shape. For more information about layout shapes, see “Layout Shapes” and related chapters in Inside Macintosh: QuickDraw GX Typography.
Drawing a Bitmap
QuickDraw GX also provides bitmap shapes, which allows you to draw certain types of images that wouldn’t be possible, or would be much more difficult, with the other shape types.
The geometry of a bitmap shape specifies the position of the bitmap and the following bitmap data:
typedef struct {
char *image;
long width;
long height;
long rowBytes;
short pixelSize;
gxColorSpace space;
gxColorSet set;
gxColorProfile profile;
}
The image field points to a block of memory that contains the pixel image. The pixelSize field indicates the size of each pixel in this image, and the width and height fields specify the dimensions, in pixels, of this image. Each pixel of the image specifies the color of one pixel in the bitmap; how this information is interpreted depends on the space, set, and profile fields.
The CreateBitmap sample function, as shown in Listing 3-14, creates a ramp—a shape that displays a smooth transition from one color to another. To create this ramp, the CreateBitmap function creates a bitmap 1 pixel tall and 256 pixels wide. It then fills in the pixel values, creating a smooth ramp from black to white through a gray color space. Finally, it scales the shape by 40 in the vertical dimension, creating a rectangular ramp.
For more information about color, see Chapter 5 in this book and the chapter “Colors and Color-related Objects” in Inside Macintosh: QuickDraw GX Objects. For more information about scaling and other shape transformations, see Chapter 6 in this book and the chapter “Transform Objects” inf Inside Macintosh: QuickDraw GX Objects.
Figure 3-10 shows the result of the CreateBitmap function.
Figure 3-10 A bitmap shape
For more information about bitmaps and bitmap shapes, see the chapter “Bitmap Shapes” of Inside Macintosh: QuickDraw GX Graphics.
Drawing a Picture
In QuickDraw GX, the picture shape is a container for other shapes—including other picture shapes, allowing you to create hierarchies of shapes. You can use picture shapes to group other shapes, as you might want to do before printing them or saving them to disk using the QuickDraw GX stream format.
Listing 3-15 shows the CreatePicture function, which creates a picture of a house. The picture has three elements: a house border, a door, and a window. The house border is a simple, single-contour polygon, the door is a rectangle, and the window is a three-contour polygon shape.
The CreatePicture function defines the geometry of each of the elements, turns those geometries into shapes using the NewPolygon, GXNewPolygons, and GXNewRectangle functions, and then adds each shape to picture using the AddToShape function. (The AddToShape and NewPolygon functions are utility functions provided in the shape library. You can use the AddToShape function to add a shape to a picture and the NewPolygon function to create a polygon shape with a single contour.)
Listing 3-15 The CreatePicture function
void CreatePicture()
{
long windowGeometry[] = {3, /* number of contours */
4, /* points in frame */
0, 0, ff(30), 0, ff(30), ff(30),
0, ff(30), /* window frame */
2, /* vertical crossbar */
ff(15), 0, ff(15), ff(30),
2, /*horizontal crossbar*/
0, ff(15), ff(30), ff(15)};
long houseGeometry[] = {7, /* # of points in house border */
Figure 3-11 shows each element, and the final result, of the CreatePicture function.
Figure 3-11 A picture shape
Listing 3-16 shows the appropriate changes to the SetUpEraserAndInvalWindow function to handle pictures. This function now uses the GXGetShapeType function to test if the current gShape shape object is a picture. If not, the function remains the same as before, copying the gShape shape to an eraser shape and setting the color of the eraser shape to white. If the gShape shape is a picture, the function creates a rectangular eraser shape just big enough to cover the picture, using the GXGetShapeBounds function.
Listing 3-16 The SetUpEraserAndInvalWindow function for picture shapes
For more information about picture shapes, see the chapter “Picture Shapes” in Inside Macintosh: QuickDraw GX Graphics.
Listing 4-0
Table 4-0
Programming With Styles
Contents
Creating a Thick Line4-3
Creating a Thick Curve4-4
Adding Dashes to a Curve4-5
Adding Caps to a Curve4-8
Adding a Pattern to a Curve4-10
Changing Text Size and Font4-13
Changing the Text Face4-14
Insetting and Outsetting the Pen4-14
Changing the Style of a Picture Element4-17
Programming With Styles
This chapter shows you how to implement functions that respond to menu items from the sample application’s Style menu. These sample drawing functions each respond to a different item of the Style menu and demonstrate a different property of the style object. The style object allows you to add stylistic variations to your QuickDraw GX shapes—variations running from line thickness to text face to patterns within a shape.
Creating a Thick Line
When QuickDraw GX draws a shape with contours (a curve, for example, or a hollow polygon), it uses the pen size property of the shape’s style object to determine how thick the contours should be.
The QuickDraw GX pen property specifies a one-dimensional thickness; conceptually, the pen is a line segment that QuickDraw GX drags along the contours of a shape when drawing it. QuickDraw GX always positions the pen so that it is perpendiclar to the contour being drawn, which causes the ends of the contour to be flat, no matter what the contour’s angle. The length of this line segment is called the pen size.
The pen size can be any fixed value, including zero, which causes QuickDraw GX to draw hairline contours. A hairline is the thinnest possible line given the resolution of a device: one device pixel wide.
Listing 4-1 shows how to set the pen size of the line shape created in Chapter 3. This function, like many of the functions in this chapter, uses one of these constants to specify the pen size:
#define kThinnerPenWidth 2
#define kThinPenWidth 5
#define kMediumPenWidth 15
#define kThickPenWidth 30
#define kVeryThickPenWidth 45
Since pen size is a fixed value, you must use the ff function with these constants.
Listing 4-1 The CreateAThickLine function
void CreateAThickLine()
{
if (GXGetShapeType(gShape) != gxLineType)
CreateLine();
else
SetUpEraserAndInvalWindow ();
GXSetShapePen (gShape, ff(kMediumPenWidth));
}
Like the CreateAFramedRectangle function, in Listing 3-7 on page 3-9, this function first tests to see if the gShape shape is already the correct type—in this case, a line. If it is not, this function calls the CreateLine function from the last chapter to create a line shape referenced by the global variable gShape.
The CreateAThickLine sample function then calls the GXSetShapePen function, which:
n determines whether the style object associated with the gShape line shape is shared with any other shapes and, if so, makes a copy the style object for the gShape line shape
n sets the pen property of the style object to the value ff(kMediumPenWidth)
Figure 4-1 shows the result of the CreateAThickLine function. Notice that QuickDraw GX positions the pen so that it is perpendicular to the line, creating flat edges at the ends of the line, even though the line is on a diagonal.
Figure 4-1 A thick line
The next section gives another example of setting the pen property.
Creating a Thick Curve
Listing 4-2 shows the CreateAThickCurve function, which uses the GXSetShapePen function to set the pen size of a curve shape.
Listing 4-2 The CreateAThickCurve function
void CreateAThickCurve()
{
if (GXGetShapeType(gShape) != gxCurveType)
CreateCurve();
else
SetUpEraserAndInvalWindow ();
GXSetShapePen (gShape, ff(kThickPenWidth));
}
Figure 4-2 shows the result of this function. Again, notice the flat edges at the ends of the curve.
Figure 4-2 A thick curve
For more information about the QuickDraw GX pen and the pen property of style objects, see the chapter “Geometric Styles” in Inside Macintosh: QuickDraw GX Graphics.
Adding Dashes to a Curve
The style object allows you to specify whether the contours of a shape should be dashed. QuickDraw GX allows dashes to be any arbitrary shape—lines, rectangles, polygons, paths, and so on. You can also specify how QuickDraw GX applies the dashes to the contour—for example, how far apart to place the dashes, where the first dash starts and whether to clip the dashes to the contour’s thickness or let them extend beyond.
QuickDraw GX even allows you to use text to dash another shape. The CreateADashedCurve function, shown in Listing 4-3, shows how to wrap the text “QuickDraw™ GX” to the curve shape defined in Chapter 3, “Programming With Shapes.”
This function creates the curve shape and then creates a dash structure, which contains the information necessary to apply the text shape to the curve shape:
typedef struct {
gxDashAttributes attributes;
gxShape dash;
fixed advance;
fract phase;
fixed scale;
} gxDashRecord;
The dash field of the dash structure contains the actual text shape (which is created using functions discussed in the section “Changing Text Size and Font” beginning on page 4-13).
For the attributes field, the gxBreakDash attribute is set, which indicates that each glyph in the text shape should be individually placed on the contour and rotated to be perpendicular to the contour’s tangent.
The advance field indicates the distance between dashes. By making this field large enough, only one dash—the complete text string—appears on the curve.
The phase field indicates how far into the text shape the dashing should start. To start at the beginning of the text, the phase should be 0.
Finally, the scale field indicates the height of the dash; in this case, the text size. QuickDraw GX maps the value of the scale field by the pen size of the shape being dashed. Since the pen size of the curve is set to 35 and the scale of the dash is 35, the text appears as 35 point.
Once the dash structure is complete, the CreateADashedCurve function adds the dash to the curve shape using the GXSetShapeDash function.
Listing 4-3 The CreateADashedCurve function
void CreateADashedCurve()
{
gxDashRecord textDash;
if (GXGetShapeType(gShape) != gxCurveType)
CreateCurve();
else
SetUpEraserAndInvalWindow ();
/* Create the gxShape that will be used to dash */
textDash.dash = GXNewText(13,
(unsigned char*)"QuickDraw™ GX",
nil);
SetShapeCommonFont(textDash.dash, timesFont);
GXSetShapeTextSize(textDash.dash, ff(35));
GXSetShapeType(textDash.dash, gxPathType);
/* Set up the dash structure */
textDash.attributes = gxBreakDash;
textDash.advance = ff(330);
textDash.phase = 0;
textDash.scale = ff(35);
/* Set up the dash structure */
GXSetShapePen(gShape, ff(35));
GXSetShapeDash (gShape, &textDash);
GXDisposeShape(textDash.dash);
}
Figure 4-3 shows the result of this function.
Figure 4-3 A dashed curve
For more information about dashing, see the chapter “Geometric Styles” in Inside Macintosh: QuickDraw GX Graphics.
For more information about text styles, see the section “Changing Text Size and Font” beginning on page 4-13 of this chapter, and the chapter “Typographic Styles” of Inside Macintosh: QuickDraw GX Typography.
Adding Caps to a Curve
Just as you can specify a dash to draw along the contours of a shape, you can also specify caps, which are shapes you want to draw at the ends of another shape’s contours.
You set the cap property of a style object using a cap structure:
typedef struct {
gxCapAttribute attributes;
gxShape startCap;
gxShape endCap;
} gxCapRecord;
The attributes field lets you specify whether the cap shapes are rotated to match the slope of the contour. Specifying gxNoAttributes indicates the caps should be rotated (the default behavior).
The startCap and endCap fields specify the actual shapes to use as the start and end caps.
Listing 4-4 shows the CreateACappedCurve function, which adds a polygon shaped like the head of an arrow and a polygon shaped like the tail of an arrow to the ends of the curve shape from previous examples.
Listing 4-4 The CreateACappedCurve function
void CreateACappedCurve()
{
gxShape arrowHead, arrowTail;
gxCapRecord theCapRecord;
long arrowHeadPolygonGeometry[] = {4, /* number of points */
-ff(2)-fix1/2, 0,
0, fix1,
fix1 + fix1/2, 0,
0, -fix1};
long arrowTailPolygonGeometry[] = {5, /* number of points */
Another property of the style object, called the join property, allows you to specify a shape to draw at the corners of another shape. For more information about caps and joins, see the chapter “Geometric Styles” in Inside Macintosh: QuickDraw GX Graphics.
Adding a Pattern to a Curve
QuickDraw GX also allows you to pattern shapes. Unlike dashes, caps, and joins, which are restricted to shapes with contours (shapes that are framed rather than filled), you can apply patterns to both framed and filled shapes.
As with dashes, caps, and joins, you can use any shape to pattern another shape. You use the pattern structure to define a pattern, and the GXSetShapePattern function to set the pattern property of a style object.
typedef struct {
gxPatternAttribute attributes;
gxShape pattern;
gxPoint u;
gxPoint v;
} gxPatternRecord;
The attributes field of this record contains flags that let you alter the behavior of the pattern.
The pattern field contains a reference to the shape to use as the pattern.
The u and v fields are vectors that, together, specify the grid to use when positioning the pattern shape.
The sample function in Listing 4-5 patterns a thick curve shape with stars. Since the u field of the pattern structure specifies a vertical vector and the v field specifies a horizontal vector, the stars are positioned in a rectangular pattern.
Listing 4-5 The CreateAPatternedCurve function
void CreateAPatternedCurve()
{
gxShape starShape;
gxRectangle starShapeBounds;
gxPatternRecord starPattern;
long starGeometry[] = { 1, /* number of contours */
The CreateAPatternedCurve function uses the GXScaleShape function to scale the star polygon down in both horizontal and vertical coordinates so that more stars appear in the curve, as shown in Figure 4-5.
Figure 4-5 A patterned curve
For more information about the pattern property of the shape object, see the chapter “Geometric Styles” in Inside Macintosh: QuickDraw GX Graphics.
Changing Text Size and Font
The style object also contains properties that apply to the typographic shapes. The sample function in Listing 4-6 shows how to change the text size and font properties.
Listing 4-6 The ChangeTextSizeAndFont function
void ChangeTextSizeAndFont()
{
if (GXGetShapeType(gShape) != gxTextType)
CreateText();
else {
SetUpEraserAndInvalWindow ();
}
GXSetShapeTextSize(gShape, ff(45));
SetShapeCommonFont(gShape, timesFont);
CenterShapeInWindow();
}
This function uses the GXSetShapeTextSize function to set the text size property of the style object associated with the gShape text shape to 45. It also uses the SetShapeCommonFont function to change the font property of the style associated with the shape. Figure 4-6 shows the result of this function. (The SetShapeCommonFont function, along with the definition for timesFont, is provided in the QuickDraw font library.)
Figure 4-6 Enlarged text
For more information about text sizes and fonts as well as many other typographic style properties, see the chapter “Fonts” and “Typographic Styles” chapters of Inside Macintosh: QuickDraw GX Typography.
You might also want to examine the contents of the font library to discover other font-related utilities provided with QuickDraw GX.
Changing the Text Face
The style object also contains a text face property. The function in Listing 4-7 uses the SetShapeCommonFace function provided in the QuickDraw GX text library to change the text face of the text shape from the previous section.
Listing 4-7 The ChangeTextStyle function
void ChangeTextStyle()
{
ChangeTextSizeAndFont();
SetShapeCommonFace(gShape, italic + extend);
}
Figure 4-7 shows the result of this function.
Figure 4-7 Italic, extended, enlarged text
For more informationabout typestyles and text faces, see the chapter “Typographic Styles” in Inside Macintosh: QuickDraw GX Typography. For examples and utilities, see the type definitions and functions provided in the text library.
Insetting and Outsetting the Pen
Like all QuickDraw GX objects, style objects have an attributes property—a set of flags that modifies the behavior of the style. The style attributes that affect graphic shapes are
n gxCenterFrameStyle
n gxSourceGridStyle
n gxDeviceGridStyle
n gxInsideFrameStyle
n gxOutsideFrameStyle
n gxAutoInsetStyle
The sample function in this section demonstrates the gxCenterFrameStyle, gxInsideFrameStyle, and gxOutsideFrameStyle attributes, which specify whether QuickDraw GX should center, inset, or outset the pen on a shape’s contours.
This sample function creates a picture containing three path shapes. Each shape has the tripleBumpGeometry from the path shape example in the previous chapter, “Programming With Shapes.” However, one path is green and has the pen inset, one is red and has it outset, and the last is blue and has the pen centered. (Chapter 5, “Programming With Inks,” discusses the color-related functions in more detail.)
The gxUniqueItemsShape attribute applies only to picture shapes and indicates that, when adding a shape to the picture, QuickDraw GX should create a copy of the shape and add the copy to the picture rather than merely adding a reference to the shape. By setting this attribute, the PenGeometryPathPlay function adds three separate path shapes to the picture—each with a different style attribute.
Figure 4-8 shows the result of this function.
Figure 4-8 Path with pen inset, centerd, and outset
For more information about style attributes, see the chapter “Geometric Styles” in Inside Macintosh: QuickDraw GX Graphics.
Changing the Style of a Picture Element
The sample functions in the previous sections of this chapter have altered a number of style objects without ever explicitly creating one. The QuickDraw GX functions GXSetShapePen, GXSetShapeDash, GXSetShapePattern, and so on, all affect style objects, but they affect style objects associated with a particular shape—you don’t have to be concerned about the style object explicitly when you use those functions.
Sometimes, however, you might want to create and alter a style object directly. The sample function in Listing 4-9 shows how to create a style object, set its pen property, and use it to affect the style of one element of a picture.
Listing 4-9 The AddThickBorderInPicture function
void AddThickBorderInPicture()
{
gxStyle thickerPen;
if (GXGetShapeType(gShape) != gxPictureType)
CreatePicture();
else
SetUpEraserAndInvalWindow();
/* Create a thicker pen style to add to the house border. */
This function creates a new style object with the GXNewStyle function and changes the pen size of the style object with the GXSetStylePen function, which is similar to the GXSetShapePen function except that it applies directly to style objects.
QuickDraw GX provides a number of functions that allow you to edit shapes once you’ve created them, one of which is the GXSetPictureParts function. The sample function uses the GXSetPictureParts function to alter a single element of the house picture from Chapter 3, “Programming With Shapes.” It uses GXSetPictureParts to replace the first item in the picture (the house border) with itself, overriding the original style of the house border with the thickerPen style. For more information about editing pictures, see the chapter “Picture Shapes” in Inside Macintosh: QuickDraw GX Graphics.
Figure 4-9 shows the result of the AddThickBorderInPicture function.
Figure 4-9 A house with a thick border
For more information about styles, the style object, and properties of the style object, see the chapter “Geometric Styles” chapter in Inside Macintosh: QuickDraw GX Graphics and the “Typographic Styles” chapter in Inside Macintosh: QuickDraw GX Typography.
Listing 5-0
Table 5-0
Programming With Inks
Contents
Drawing a Blue Curve5-3
Blending Two Shapes5-4
Changing the Ink of a Picture Element5-6
Programming With Inks
The QuickDraw GX ink object allows you to specify color and color-transfering information for your shapes. The sample drawing functions in this chapter each respond to a different item of the Ink menu and demonstrate the two main properties of the ink object: color and transfer mode.
Drawing a Blue Curve
QuickDraw GX provides a sophisticated and intricate color model, described in detail in Inside Macintosh: QuickDraw GX Objects. However, you don’t need to understand the entire color model to start drawing in color. The QuickDraw GX color library provides many convenient type definitions and utility functions that greatly simplify drawing in color.
Listing 5-1 shows a function that draws the curve shape from earlier examples in blue. To do this, it creates a new ink object, sets the color property of that ink object to blue using the color library function SetInkCommonColor and value blue, and attaches the ink object to the curve shape referenced by gShape.
Listing 5-1 The CreateABlueCurve function
void CreateABlueCurve()
{
gxInk blueInk;
if (GXGetShapeType(gShape) != gxCurveType)
CreateCurve();
else
SetUpEraserAndInvalWindow ();
GXSetShapePen(gShape, ff(kMediumPenWidth));
blueInk = GXNewInk ();
SetInkCommonColor(blueInk, blue);
GXSetShapeInk(gShape, blueInk);
GXDisposeInk(blueInk);
}
Figure 5-1 shows the result of this function (as rendered on a black-and-white device).
Figure 5-1 A blue curve
For information about the QuickDraw GX color model, see the chapters “Colors and Color-Related Objects” and “Ink Objects” in Inside Macintosh: QuickDraw GX Objects. For utilities and examples, see the color library.
Blending Two Shapes
Besides color, the other main property of the ink object is its transfer mode. A shape’s transfer mode determines how the color of the shape (the source color) interacts with the color of the background (the destination color) over which QuickDraw GX draws the shape. As with color, the transfer mode model is powerful and intricate: the transfer mode structure contains
n information about the color space in which the transfer happens
n three filters, in the form of 5 by 4 matrices, that can be used to modify the source, destination, and result colors before and after the transfer occurs
n up to four transfer mode components, that independently specify the transfer mode for each component (such as red, geeen, or blue) in the color space
n a set of flags that affect the transfer
The sample function in Listing 5-2 shows the simplest case of a transfer mode. This function specifies gxRgbSpace as the transfer mode’s color space, sets the gxSingleComponentTransfer flag (which indicates that a single transfer mode is to be used for all four transfer mode components), and specifies that the transfer mode be gxBlendMode, which indicates that the source color and background color should be blended.
This function creates a picture with two overlapping curve shapes. The first curve shape references the default ink object and the second curve shape references an ink object with an altered transfer mode. The sample function uses the GXSetShapeTransfer function to set the transfer mode of the second curve’s ink object.
Figure 5-2 shows the result of this function.
Figure 5-2 Blended curves
For more information about transfer modes, see the chapter “Ink Objects” in Inside Macintosh: QuickDraw GX Objects.
Changing the Ink of a Picture Element
In the last chapter, you used the GXSetPictureParts function to change the pen size of the house border in the house picture. In this section, you’ll use GXSetPictureParts to change the color of the house picture’s door.
The sample function in Listing 5-3 creates an ink object, uses the SetInkCommonColor function from the color library to change the color property of the ink object, and overrides the door shape’s existing ink object with the new ink object.
For more information about inks, the ink object, and the properties of the ink object, see the chapter “Ink Objects” in Inside Macintosh: QuickDraw GX Objects. For more information about the QuickDraw GX color model, see the chapter “Colors and Color-Related Objects,” also in Inside Macintosh: QuickDraw GX Objects.
Listing 6-0
Table 6-0
Programming With Transforms
Contents
Clipping a Curve6-3
Rotating a Curve6-5
Skewing Text6-7
Transforming an Element of a Picture6-8
Hit-Testing6-9
Programming With Transforms
This chapter shows you how to implement the functions that respond to the menu items of the sample application’s Transform menu. The sample functions in this chapter each respond to a different menu item and demonstrate a different property of the transform object.
The transform object has four main properties:
n clip
n mapping
n view port list
n hit-test parameters
This chapter gives examples of mapping, clipping, and hit-testing. For information about view ports, see the chapter “View-Related Objects” in Inside Macintosh: QuickDraw GX Objects.
Clipping a Curve
The clip property of a shape’s transform object determines how much of the shape QuickDraw GX actually draws. The clip property contains the clip shape. When QuickDraw GX draws a shape, it draws only the parts of the shape that intersect with the shape’s clip shape.
The clip shape is a QuickDraw GX shape—you can use rectangles, polygons, paths, and so on as clip shapes. The sample function in Listing 6-1 uses an irregularly shaped path (an “oval wabble,” which is pictured in Figure 6-1) to clip the curve shape from previous sections.
Listing 6-1 The ClipCurve function
void ClipCurve()
{
gxShape newClipShape;
long ovalWabbleGeometry[] = {1, // number of contours
x = clipBoundsShape.left + clipBoundsShape.right >> 1;
y = clipBoundsShape.top + clipBoundsShape.bottom >> 1;
GXRotateShape(newClipShape, ff(90), x, y);
GXGetShapeBounds(gShape, 0L, &curveBoundsShape);
x = curveBoundsShape.left;
y = curveBoundsShape.top;
GXMoveShapeTo(newClipShape, x, y);
GXSetShapeClip(gShape, newClipShape);
GXDisposeShape(newClipShape);
}
The ClipCurve sample function creates the curve shape, which is the shape to be clipped, and the wabble shape, which is the clip shape. (The clip shape is rotated and moved in this example so that it actually intersects with curve shape.) The sample function then uses the GXSetShapeClip function to set the clip of the curve shape’s transform.
Figure 6-1 shows the steps of the clipping process and the final result of the function.
Figure 6-1 A clipped curve
For more information about clipping, see the chapter “Transform Objects” in Inside Macintosh: QuickDraw GX Graphics.
Rotating a Curve
The mapping property of a shape’s transform object is a 3-by-3 matrix that QuickDraw GX applies to each control point of the shape’s geometry before drawing the shape. Although QuickDraw GX allows you to specify the components of this matrix directly, it also provides a number of functions that create an appropriate matrix for you—for example, the GXRotateShape function.
The GXRotateShape function allows you to rotate a shape by a specified number of degrees. To perform the rotation, the GXRotateShape function takes one of the following approaches:
n If the gxMapTransformShape attribute of the shape object is set, GXRotateShape performs the rotation by setting the mapping property of the shape’s transform to an appropriate mapping matrix. The original control points of the shape’s geometry are not affected.
n If the gxMapTransformShape attribute of the shape object is not set, GXRotateShape performs the rotation by changing the control points of shape’s geometry directly.
By default, this attribute is set for bitmap shapes and clear for other types of shapes.
Listing 6-2 shows the RotateCurve sample function, which uses the GXRotateShape function to create a mapping matrix that rotates the curve shape by 90 degrees.
x = (curveBoundsShape.left + curveBoundsShape.right) >> 1;
y = (curveBoundsShape.top + curveBoundsShape.bottom) >> 1;
GXRotateShape(gShape, ff(90), x, y);
}
Notice that the parameters to the GXRotateShape function specify the shape to rotate, the desired angle of rotation, and the point about which to rotate the shape (which, in this case, is the center of the curve shape).
Figure 6-2 shows the result of this function.
Figure 6-2 A rotated curve
For more information about the mapping property of transform objects and other mapping utility functions, see the chapter “Transform Objects” in Inside Macintosh: QuickDraw GX Objects.
Skewing Text
Since the typographic shapes are full-fledged QuickDraw GX shapes, they also reference transform objects, and the clip and mapping properties apply to them as well.
The SkewText sample function, shown in Listing 6-3, demonstrates the GXSkewShape function, which skews a shape by altering its control points directly or by altering the mapping property of its transform object—depending on the gxMapTransformShape shape attribute. The parameters of the GXSkewShape function specify how much to skew the shape in each dimension and the point about which to skew the shape.
Listing 6-3 The SkewText function
void SkewText()
{
fixed x,y;
gxRectangle textBoundsShape;
ChangeTextSizeAndFont();
GXGetShapeBounds(gShape, 0L, &textBoundsShape);
x = textBoundsShape.left;
x = textBoundsShape.left + textBoundsShape.right >> 1;
y = textBoundsShape.top + textBoundsShape.bottom >> 1;
GXSkewShape(gShape, fl(1.5), 0, x, y);
}
Figure 6-3 shows the result of this function.
Figure 6-3 Skewed text
Transforming an Element of a Picture
The GXSetPictureParts function, which you’ve seen in the previous two chapters, also allows you to override the transform object of a picture element.
The AddNewWindowToPicture sample function, shown in Listing 6-4, shows how to override a picture element’s transform so that the element appears twice in the picture. This function creates a transform object and alters its mapping property using the GXScaleTransform and GXMoveTransform functions. Then, it creates the picture of the house from the previous chapters and extracts a reference to the window shape using the GXGetPictureParts function. Finally, it adds the window shape back to the picture with an overriding transform object—making the new window appear in a different place within the house.
For more information about adding elements to pictures with overriding transform objects, see the “Picture Shapes” chapter of Inside Macintosh: QuickDraw GX Graphics.
Hit-Testing
The transform object also contains a hit-test property, which determines how shapes that share the transform are hit-tested. For example, the information included in the hit-test property determines what parts of a shape are hit-tested and how close a mouse click must be to qualify as a hit. You can manipulate the hit-test parameters using the GXGetTransformHitTest and GXSetTransformHitTest functions, which are described in the “Transform Objects” chapter of Inside Macintosh: QuickDraw GX Objects.
The functions that actually perform hit-testing are GXHitTestShape, GXHitTestPicture, and GXHitTestLayout.
The function in Listing 6-5 creates a layout shape and then uses the GXHitTestLayout function to determine which character of the layout corresponds to the location where the user clicked the mouse. It uses the information, and the GXGetLayoutCaret function, to draw a caret at the appropriate point in the layout.
Listing 6-5 The HitTestLayoutCaret function
void HitTestLayoutCaret(theHitPoint)
gxPoint theHitPoint;
{
gxLayoutHitInfo theLayoutHitInfo;
gxByteOffset theCharacterOffset;
static gxBoolean caretWasDrawn;
/*
The caret has been drawn before. Therefore we erase
the"old" caret before we draw the new one.
*/
if (caretWasDrawn) {
SetShapeCommonTransfer(gLayoutCaret, gxCopyMode);
GXDrawShape(gLayoutCaret);
GXDisposeShape(gLayoutCaret);
}
theLayoutHitInfo.hitTrackingArea = nil;
/* Otherwise, QuickDraw GX would try to use a garbage shape. */
This call will cause the layout and the caret to be redrawn.
This prevents streaks from appearing in our layout gxShape.
*/
InvalidWindowRect ();
caretWasDrawn = true;
}
The GXHitTestLayout function returns the character offset corresponding to the location of the mouse click, which the GXGetLayoutCaret function uses to create and position a caret shape.
To reference the caret shape, the sample function introduces a new global variable, gLayoutCaret, which is declared in the QD GX Overview Draw.c file and handle similarly to the other global shapes in the DoInitialize, DoDraw, and DoDispose functions.
Figure 6-5 shows the result of this function after the user clicks the mouse between the Q and the u of the word QuickDraw.
Figure 6-5 A layout with a caret
For more information about hit-testing and hit-testing parameters, see the chapters “Shape Objects” and “Transform Objects” in Inside Macintosh: QuickDraw GX Objects. For information specific to hit-testing picture shapes, see the chapter “Picture Shapes” in Inside Macintosh: QuickDraw GX Graphics. For information specific to hit-testing layout shapes, see the chapter “Layout Shapes” in Inside Macintosh: QuickDraw GX Typography.
Listing 7-0
Table 7-0
Printing
Contents
Preparing to Print7-3
Setting Up a Document7-4
Printing One Copy7-5
Displaying the Print Dialog Box7-7
Printing
This chapter introduces some key concepts of the QuickDraw GX printing architecture. In particular, it shows how to display the Document Setup dialog box and the Print dialog box, and it shows one approach to printing your QuickDraw GX shapes.
For a complete discussion of the QuickDraw GX printing architecture, see Inside Macintosh: QuickDraw GX Printing. You might also want to read Inside Macintosh: QuickDraw GX Printing Extensions and Drivers for information about creating your own printing extensions and printer drivers.
IMPORTANT
You should create a desktop printer with the Chooser before including the functions from this chapter in your sample application. See Inside Macintosh: QuickDraw GX Printing for details.s
Preparing to Print
Before your application can print, you must call the EnterPrinting function. Typically, you call this function immediately after calling the GXEnterGraphics function. Similarly, you should call the GXExitPrinting function before calling the GXExitGraphics function.
The QuickDraw GX printing architecture provides the job object to contain printing-related information. Each job object is tied to a single driver/printer pair and maintains this association until the user changes it through the Print dialog box, which is described later in this chapter. Before your application can print, it must create a new job object, and when through with all printing for a given document, it should dispose of the job object. The shell program of the sample application calls the CreateNewPrintJob function at application startup time and the DisposePrintJob function before the application quits. These functions, shown in Listing 7-1 and Listing 7-2, are included in the QD GX Overview Draw.c file.
Listing 7-1 The CreateNewPrintJob function
void CreateNewPrintJob ()
{
OSErr printError;
printError = GXNewJob(&gDocumentJob);
if (printError != noErr)
DebugStr("\p Error in GXNewJob");
}
This sample function simply calls the GXNewJob funtion to create a new job object, which is referenced by the global variable gDocumentJob:
gxJob gDocumentJob;
Note that in your application you should provide more error handling than provided by this sample function.
Listing 7-2 The DisposePrintJob function
void DisposePrintJob ()
{
OSErr printError;
printError = GXDisposeJob(gDocumentJob);
if (printError != noErr) DebugStr("\p Blam! GXDisposeJob");
}
This function calls the GXDisposeJob function to dispose of the gDocumentJob object.
Setting Up a Document
In the QuickDraw GX printing architecture, the Page Setup dialog box is replaced by the Document Setup dialog box, which is shown in Figure 7-1.
Figure 7-1 The Document Setup dialog box
When the user of the sample application chooses the Document Setup menu item from the File menu, the shell program calls the DoDocumentSetUp function, which is shown in Listing 7-3. This sample function displays the Document Setup dialog box by calling the JobFormatDialog function.
Listing 7-3 The DoDocumentSetUp function
OSErr DoDocumentSetUp ()
{
OSErr printError;
gxDialogResult result;
gxEditMenuRecord editMenuRecord;
printError = noErr;
SetUpEditMenuRec(&editMenuRecord);
result = JobFormatDialog(gDocumentJob, &editMenuRecord);
if (GXGetJobError(gDocumentJob) != noErr)
DebugStr("\p Error in JobFormatDialog");
return printError;
}
For more information about jobs, documents, and the Document Setup dialog box, see the chapters “Introduction to Printing With QuickDraw GX” and “Core Printing Features” in Inside Macintosh: QuickDraw GX Printing.
Printing One Copy
QuickDraw GX provides two methods for printing. The sample function in Listing 7-4 demonstrates one of these methods: collecting all the shapes on a page into a picture, and then printing the picture with the GXPrintPage function. (The other method consists basically of setting up to print a page and then calling GXDrawShape in turn for each shape on the page.)
Before you begin printing with the GXPrintPage function, you should call the GXStartJob function; when you are finished printing, you should call the GXFinishJob function.
This function creates an empty picture shape and adds to it the shape referenced by the gShape global variable. Then it determines the title of the sample application window and sends it to the GXStartJob function, which causes the GXStartJob function to name the print job after the window. (QuickDraw GX uses the job name when displaying status dialog boxes.)
The sample function then prints the page using the GXPrintPage function and finishes printing by calling the GXFinishJob function.
Displaying the Print Dialog Box
The previous section showed you how to print one copy of the shape displayed by the sample application. In this section, you’ll learn how to display the Print dialog box before printing.
Figure 7-2 shows the Print dialog box.
Figure 7-2 The Print dialog box
The sample function in Listing 7-5 displays the Print dialog box by calling the GXJobPrintDialog function. If the user selects the Print button from the dialog box, this function then calls the DoPrintOneCopy sample funtion from the previous section to print the current shape.
Listing 7-5 The DoPrintShape function
OSErr DoPrintShape(window)
WindowPtr window;
{
OSErr printError;
gxDialogResult result;
gxEditMenuRecord editMenuRecord;
printError = noErr;
SetUpEditMenuRec(&editMenuRecord);
if (window) {
if (GXJobPrintDialog(gDocumentJob,
&editMenuRecord) == gxOkSelected) {
printError = GXGetJobError(gDocumentJob);
if (!(printError))
printError = DoPrintOneCopy(window);
}
}
return printError;
}
For more information about the Print dialog box or printing in general, see Inside Macintosh: QuickDraw GX Printing.